package com.platform.web.controller.module;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.platform.common.annotation.Log;
import com.platform.common.core.controller.BaseController;
import com.platform.common.core.domain.AjaxResult;
import com.platform.common.core.domain.Ztree;
import com.platform.common.core.page.TableDataInfo;
import com.platform.common.core.text.Convert;
import com.platform.common.enums.BusinessType;
import com.platform.common.utils.netty.ChannelSupervise;
import com.platform.common.utils.netty.NettyUtil;
import com.platform.common.utils.poi.ExcelUtil;
import com.platform.common.utils.redis.RedisRun;
import com.platform.common.utils.redis.RedisUtil;
import com.platform.framework.util.ShiroUtils;
import com.platform.module.domain.*;
import com.platform.module.service.*;
import com.platform.system.service.ISysDictDataService;
import io.netty.channel.Channel;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.text.ParseException;
import java.util.*;
import java.util.concurrent.CountDownLatch;

/**
 * 阀门设备数据Controller
 * 
 * @author wangqi
 * @date 2020-07-13
 */
@Controller
@RequestMapping("/module/valve/data")
public class BaseValveDataController extends BaseController
{
    private String prefix = "module/valve/data";

    @Autowired
    private ILinkConcentratorValveService linkConcentratorValveService;

    @Autowired
    private IBaseValveDataService baseValveDataService;

    @Autowired
    private IBaseValveTypeService baseValveTypeService;

    @Autowired
    private ISysDictDataService sysDictDataService;

    @Autowired
    private RedisUtil redisUtil;

    @RequiresPermissions("module:valve:data:view")
    @GetMapping("/{typeId}")
    public String data(@PathVariable("typeId") Long typeId, ModelMap mmap)
    {
        BaseValveType baseValveType = new BaseValveType();
        if(typeId != 0L){
            baseValveType = baseValveTypeService.getById(typeId);
        }
        mmap.put("type", baseValveType);
        mmap.put("valveList", baseValveTypeService.list());
        return prefix + "/data";
    }

    /**
     * 查询阀门设备数据列表
     */
    @RequiresPermissions("module:valve:data:list")
    @PostMapping("/list")
    @ResponseBody
    public TableDataInfo list(BaseValveData baseValveData)
    {
        startPage();
        List<BaseValveData> list = baseValveDataService.selectBaseValveDataList(baseValveData);
        return getDataTable(list);
    }

    /**
     * 导出阀门设备数据列表
     */
    @RequiresPermissions("module:valve:data:export")
    @Log(title = "阀门设备数据", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    @ResponseBody
    public AjaxResult export(BaseValveData baseValveData)
    {
        List<BaseValveData> list = baseValveDataService.selectBaseValveDataList(baseValveData);
        ExcelUtil<BaseValveData> util = new ExcelUtil<BaseValveData>(BaseValveData.class);
        for(BaseValveData data : list){
            String status = sysDictDataService.selectDictLabel("status", data.getStatus());
            data.setStatus(status);
        }
        return util.exportExcel(list, "阀门资料");
    }

    /**
     * @Author 王琦
     * @Description //阀门型号信息导入
     * @Date 2020/6/19 19:56
     * @Param [file, updateSupport]
     * @return com.platform.common.core.domain.AjaxResult
     */
    @Log(title = "阀门数据导入", businessType = BusinessType.IMPORT)
    @RequiresPermissions("module:valve:data:import")
    @PostMapping("/importData")
    @ResponseBody
    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
    {
        ExcelUtil<BaseValveData> util = new ExcelUtil<BaseValveData>(BaseValveData.class);
        List<BaseValveData> valveDataList = util.importExcel(file.getInputStream());
        String operName = ShiroUtils.getSysUser().getLoginName();
        String message = baseValveDataService.importBaseValveData(valveDataList, updateSupport, operName);
        return AjaxResult.success(message);
    }

    /**
     * @Author 王琦
     * @Description //导入模板
     * @Date 2020/6/19 19:56
     * @Param []
     * @return com.platform.common.core.domain.AjaxResult
     */
    @GetMapping("/importTemplate")
    @ResponseBody
    public AjaxResult importTemplate()
    {
        ExcelUtil<BaseValveData> util = new ExcelUtil<BaseValveData>(BaseValveData.class);
        return util.importTemplateExcel("阀门信息");
    }

    /**
     * 新增阀门设备数据
     */
    @GetMapping("/add/{typeId}")
    public String add(@PathVariable("typeId") Long typeId, ModelMap mmap)
    {
        List<BaseValveType> valveList = baseValveTypeService.list();
        mmap.put("valveList", valveList);
        mmap.put("typeId", typeId);
        return prefix + "/add";
    }

    /**
     * 新增保存阀门设备数据
     */
    @RequiresPermissions("module:valve:data:add")
    @Log(title = "阀门设备数据", businessType = BusinessType.INSERT)
    @PostMapping("/add")
    @ResponseBody
    public AjaxResult addSave(BaseValveData baseValveData)
    {
        baseValveData.setCreateBy(ShiroUtils.getLoginName());
        return toAjax(baseValveDataService.insertBaseValveData(baseValveData));
    }

    /**
     * 修改阀门设备数据
     */
    @GetMapping("/edit/{valveId}")
    public String edit(@PathVariable("valveId") String valveId, ModelMap mmap)
    {
        BaseValveData baseValveData = baseValveDataService.getById(valveId);
        mmap.put("baseValveData", baseValveData);
        List<BaseValveType> valveList = baseValveTypeService.list();
        mmap.put("valveList", valveList);
        return prefix + "/edit";
    }

    /**
     * 修改保存阀门设备数据
     */
    @RequiresPermissions("module:valve:data:edit")
    @Log(title = "阀门设备数据", businessType = BusinessType.UPDATE)
    @PostMapping("/edit")
    @ResponseBody
    public AjaxResult editSave(BaseValveData baseValveData)
    {
        baseValveData.setUpdateBy(ShiroUtils.getLoginName());
        return toAjax(baseValveDataService.updateBaseValveData(baseValveData));
    }

    /**
     * 删除阀门设备数据
     */
    @RequiresPermissions("module:valve:data:remove")
    @Log(title = "阀门设备数据", businessType = BusinessType.DELETE)
    @PostMapping( "/remove")
    @ResponseBody
    public AjaxResult remove(String ids)
    {
        return toAjax(baseValveDataService.deleteBaseValveDataByIds(ids));
    }

    /**
     * 阀门登记
     */
    @Log(title = "阀门登记", businessType = BusinessType.GRANT)
    @RequiresPermissions("module:valve:data:register")
    @PostMapping("/register")
    @ResponseBody
    public AjaxResult register(String valveIds) throws InterruptedException {
        List<String> ids = Arrays.asList(Convert.toStrArray(valveIds));
        StringBuilder failureMsg = new StringBuilder();
        for(String valveId : ids){
            String concentratorId = "";

            if(redisUtil.hHasKey("concentratorValve", valveId)){
                concentratorId = redisUtil.hget("concentratorValve", valveId).toString();
            }else{
                failureMsg.append("阀门"+valveId+"未关联采集器，请先关联采集器");
                break;
            }

            boolean status = redisUtil.hHasKey("sys-netty", concentratorId);
            if(!status){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }
            //获取采集器高位
            String cenhigh = concentratorId.substring(0,2);
            //获取采集器低位
            String cenlow = concentratorId.substring(2,4);

            //获取通道id
            String channelId = redisUtil.hget("sys-netty",cenhigh+cenlow).toString();
            Channel channel = ChannelSupervise.findChannel(channelId);
            if(channel==null){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }

            String high = valveId.substring(0,2);
            String low = valveId.substring(2,4);
            //控制码
            String cont = "03";
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(high)+NettyUtil.get10HexNum(low)+NettyUtil.get10HexNum(cont);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA " + cenlow + " " + cenhigh + " 00 00 " + low + " " + high + " " + cont + " 00 00 00 00 00 00 " + check + " FF ";
            String revertStr = response.replace(" ", "");
            NettyUtil.writeToClient(revertStr,channel,"阀门登记");
            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch,redisUtil,valveId,cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            if(result.equals("00") || result.equals("01")){
                LinkConcentratorValve linkConcentratorValve = new LinkConcentratorValve();
                linkConcentratorValve.setValveId(valveId);
                linkConcentratorValve.setConcentratorId(concentratorId);
                linkConcentratorValve.setStatus("1");
                linkConcentratorValveService.updateLinkConcentratorValve(linkConcentratorValve);
            }else{
                failureMsg.append("<br/>阀门"+valveId+"登记失败");
            }
        }
        if(failureMsg.toString().equals("")){
            return AjaxResult.success();
        }else{
            return AjaxResult.error(failureMsg.toString());
        }
    }

    /**
     * 阀门登记
     */
    @Log(title = "阀门注销", businessType = BusinessType.GRANT)
    @RequiresPermissions("module:valve:data:cancel")
    @PostMapping("/cancel")
    @ResponseBody
    public AjaxResult cancel(String valveIds) throws InterruptedException {
        List<String> ids = Arrays.asList(Convert.toStrArray(valveIds));
        StringBuilder failureMsg = new StringBuilder();
        for(String valveId : ids){
            String concentratorId = "";

            if(redisUtil.hHasKey("concentratorValve", valveId)){
                concentratorId = redisUtil.hget("concentratorValve", valveId).toString();
            }else{
                failureMsg.append("阀门"+valveId+"未关联采集器，请先关联采集器");
                break;
            }

            boolean status = redisUtil.hHasKey("sys-netty", concentratorId);
            if(!status){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }
            //获取采集器高位
            String cenhigh = concentratorId.substring(0,2);
            //获取采集器低位
            String cenlow = concentratorId.substring(2,4);

            //获取通道id
            String channelId = redisUtil.hget("sys-netty",cenhigh+cenlow).toString();
            Channel channel = ChannelSupervise.findChannel(channelId);
            if(channel==null){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }

            String high = valveId.substring(0,2);
            String low = valveId.substring(2,4);
            //控制码
            String cont = "04";
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(high)+NettyUtil.get10HexNum(low)+NettyUtil.get10HexNum(cont);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA " + cenlow + " " + cenhigh + " 00 00 " + low + " " + high + " " + cont + " 00 00 00 00 00 00 " + check + " FF ";
            String revertStr = response.replace(" ", "");
            NettyUtil.writeToClient(revertStr,channel,"阀门注销");
            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch,redisUtil,valveId,cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            if(result.equals("00") || result.equals("02")){
                LinkConcentratorValve linkConcentratorValve = new LinkConcentratorValve();
                linkConcentratorValve.setValveId(valveId);
                linkConcentratorValve.setConcentratorId(concentratorId);
                linkConcentratorValve.setStatus("0");
                linkConcentratorValveService.updateLinkConcentratorValve(linkConcentratorValve);
            }else{
                failureMsg.append("<br/>阀门"+valveId+"注销失败");
            }
        }
        if(failureMsg.toString().equals("")){
            return AjaxResult.success();
        }else{
            return AjaxResult.error(failureMsg.toString());
        }
    }

    /**
     * 设置阀门开度
     */
    @GetMapping("/aperture/{valveIds}")
    public String aperture(@PathVariable("valveIds") String valveIds, ModelMap mmap)
    {
        mmap.put("valveIds",valveIds);
        return prefix + "/aperture";
    }

    /**
     * 设置阀门开度
     */
    @Log(title = "设置阀门开度", businessType = BusinessType.GRANT)
    @RequiresPermissions("module:valve:data:aperture")
    @PostMapping("/aperture")
    @ResponseBody
    public AjaxResult aperture(BaseValveData valve) throws InterruptedException {
        List<String> ids = Arrays.asList(Convert.toStrArray(valve.getValveIds()));
        String hex = NettyUtil.get16HexNum(valve.getAperture());
        if(hex.length()<2){
            hex = "0" + hex;
        }
        StringBuilder failureMsg = new StringBuilder();
        for(String valveId : ids){
            String concentratorId = "";

            if(redisUtil.hHasKey("concentratorValve", valveId)){
                concentratorId = redisUtil.hget("concentratorValve", valveId).toString();
            }else{
                failureMsg.append("阀门"+valveId+"未关联采集器，请先关联采集器");
                break;
            }

            boolean status = redisUtil.hHasKey("sys-netty", concentratorId);
            if(!status){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }
            //获取采集器高位
            String cenhigh = concentratorId.substring(0,2);
            //获取采集器低位
            String cenlow = concentratorId.substring(2,4);

            //获取通道id
            String channelId = redisUtil.hget("sys-netty",cenhigh+cenlow).toString();
            Channel channel = ChannelSupervise.findChannel(channelId);
            if(channel==null){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }

            String high = valveId.substring(0,2);
            String low = valveId.substring(2,4);
            //控制码
            String cont = "02";
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(high)+NettyUtil.get10HexNum(low)+NettyUtil.get10HexNum(cont)+NettyUtil.get10HexNum(hex);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA " + cenlow + " " + cenhigh + " 00 00 " + low + " " + high + " " + cont + " " + hex + " 00 00 00 00 00 " + check + " FF ";
            String revertStr = response.replace(" ", "");
            NettyUtil.writeToClient(revertStr,channel,"设置阀门开度");

            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch,redisUtil,valveId,cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            if(result.equals("00")){
                BaseValveData baseValveData = baseValveDataService.getById(valveId);
                baseValveData.setAperture(valve.getAperture());
                baseValveDataService.updateBaseValveData(baseValveData);
            }else{
                failureMsg.append("<br/>阀门"+valveId+"设置阀门开度失败");
            }
        }
        if(failureMsg.toString().equals("")){
            return AjaxResult.success();
        }else{
            return AjaxResult.error(failureMsg.toString());
        }
    }

    /**
     * 读取阀门数据
     */
    @Log(title = "读取阀门数据", businessType = BusinessType.GRANT)
    @RequiresPermissions("module:valve:data:check")
    @PostMapping("/check")
    @ResponseBody
    public AjaxResult check(String valveIds) throws InterruptedException, ParseException {
        List<String> ids = Arrays.asList(Convert.toStrArray(valveIds));
        StringBuilder failureMsg = new StringBuilder();
        for(String valveId : ids){
            String concentratorId = "";

            if(redisUtil.hHasKey("concentratorValve", valveId)){
                concentratorId = redisUtil.hget("concentratorValve", valveId).toString();
            }else{
                failureMsg.append("阀门"+valveId+"未关联采集器，请先关联采集器");
                break;
            }

            boolean status = redisUtil.hHasKey("sys-netty", concentratorId);
            if(!status){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }
            //获取采集器高位
            String cenhigh = concentratorId.substring(0,2);
            //获取采集器低位
            String cenlow = concentratorId.substring(2,4);

            //获取通道id
            String channelId = redisUtil.hget("sys-netty",cenhigh+cenlow).toString();
            Channel channel = ChannelSupervise.findChannel(channelId);
            if(channel==null){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }

            String high = valveId.substring(0,2);
            String low = valveId.substring(2,4);
            //控制码
            String cont = "01";
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(high)+NettyUtil.get10HexNum(low)+NettyUtil.get10HexNum(cont);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA " + cenlow + " " + cenhigh + " 00 00 " + low + " " + high + " " + cont + " 00 00 00 00 00 00 " + check + " FF ";
            String revertStr = response.replace(" ", "");
            NettyUtil.writeToClient(revertStr,channel,"读取阀门数据");

            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch,redisUtil,valveId,cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            if(!result.equals("00")){
                failureMsg.append("<br/>阀门"+valveId+"读取阀门数据失败");
            }
        }
        if(failureMsg.toString().equals("")){
            return AjaxResult.success();
        }else{
            return AjaxResult.error(failureMsg.toString());
        }
    }

    /**
     * 读取阀门数据
     */
    @Log(title = "限制阀门开启", businessType = BusinessType.GRANT)
    @RequiresPermissions("module:valve:data:limit")
    @PostMapping("/limit")
    @ResponseBody
    public AjaxResult limit(String valveIds) throws InterruptedException, ParseException {
        List<String> ids = Arrays.asList(Convert.toStrArray(valveIds));
        StringBuilder failureMsg = new StringBuilder();
        for(String valveId : ids){
            String concentratorId = "";

            if(redisUtil.hHasKey("concentratorValve", valveId)){
                concentratorId = redisUtil.hget("concentratorValve", valveId).toString();
            }else{
                failureMsg.append("阀门"+valveId+"未关联采集器，请先关联采集器");
                break;
            }

            boolean status = redisUtil.hHasKey("sys-netty", concentratorId);
            if(!status){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }
            //获取采集器高位
            String cenhigh = concentratorId.substring(0,2);
            //获取采集器低位
            String cenlow = concentratorId.substring(2,4);

            //获取通道id
            String channelId = redisUtil.hget("sys-netty",cenhigh+cenlow).toString();
            Channel channel = ChannelSupervise.findChannel(channelId);
            if(channel==null){
                failureMsg.append("采集器"+concentratorId+"已离线，请联系现场维护人员重启采集器");
                break;
            }

            String high = valveId.substring(0,2);
            String low = valveId.substring(2,4);
            //控制码
            String cont = "09";
            //计算校验码
            int ll = NettyUtil.get10HexNum(cenhigh)+NettyUtil.get10HexNum(cenlow)+NettyUtil.get10HexNum(high)+NettyUtil.get10HexNum(low)+NettyUtil.get10HexNum(cont);
            String check = NettyUtil.get16HexNum(ll);
            if(check.length()<2){
                check = "0" + check;
            }else{
                check = check.substring(check.length()-2);
            }
            String response = "AA " + cenlow + " " + cenhigh + " 00 00 " + low + " " + high + " " + cont + " 00 00 00 00 00 00 " + check + " FF ";
            String revertStr = response.replace(" ", "");
            NettyUtil.writeToClient(revertStr,channel,"限制阀门开启");

            CountDownLatch countDownLatch = new CountDownLatch(1);
            new Thread(new RedisRun(countDownLatch,redisUtil,valveId,cont)).start();
            countDownLatch.await();
            String result = RedisRun.result;
            if(!result.equals("00")){
                failureMsg.append("<br/>阀门"+valveId+"限制开启失败");
            }
        }
        if(failureMsg.toString().equals("")){
            return AjaxResult.success();
        }else{
            return AjaxResult.error(failureMsg.toString());
        }
    }

    /**
     * 校验厂商代码
     */
    @PostMapping("/checkValveDataCodeUnique")
    @ResponseBody
    public String checkValveDataCodeUnique(BaseValveData baseValveData)
    {
        return baseValveDataService.checkValveDataCodeUnique(baseValveData);
    }

    /**
     * 加载阀门数列表
     */
    @GetMapping("/treeData")
    @ResponseBody
    public List<Ztree> treeData()
    {
        List<Ztree> ztrees = baseValveDataService.selectValveTree();
        return ztrees;
    }
}
